module ModuleCreationHelper
  module Extensions #:nodoc:
    # Adds helper methods for easily generating new modules/classes
    module Module
      # Creates a new module with the specified name.  This is essentially the
      # same as actually defining the module like so:
      # 
      #   module NewModule
      #   end
      # 
      # or as a class:
      # 
      #   class NewClass < SuperKlass
      #   end
      # 
      # Configuration options:
      # * <tt>:superclass</tt> - The class to inherit from.  This only applies
      #   when using Class#create.  Default is Object.
      # * <tt>:parent</tt> - The class/module that contains this module.
      #   Default is Object.
      # 
      # == Examples
      # 
      #   Module.create('Foo')                                                      # => Foo
      #   Module.create('Bar', :parent => Foo)                                      # => Foo::Bar
      #   Class.create('Waddle')                                                    # => Waddle
      #   Class.create('Widdle', :parent => Waddle)                                 # => Waddle::Widdle
      #   Class.create('Woddle', :superclass => Waddle::Widdle, :parent => Waddle)  # => Waddle::Woddle
      #   Waddle::Woddle.superclass                                                 # => Waddle::Widdle
      # 
      # == Setting the parent
      # 
      # Rather than setting the parent directly using the +parent+ configuration
      # option, you can specify it in the actual name of the class like so:
      # 
      #   Module.create('Foo::Bar')   # => Foo::Bar
      # 
      # This has the same effect as the following:
      # 
      #   Module.create('Bar', :parent => Foo)
      def create(name, options = {}, &block)
        # Validate the provided options
        invalid_options = options.keys - [:superclass, :parent]
        raise ArgumentError, "Unknown key(s): #{invalid_options.join(", ")}" unless invalid_options.empty?
        
        # Validate usage of :superclass option
        raise ArgumentError, 'Modules cannot have superclasses' if options[:superclass] && self.to_s == 'Module'
        
        options = {:superclass => Object, :parent => Object}.merge(options)
        parent = options[:parent]
        superclass = options[:superclass]
        
        if superclass != Object
          superclass = " < ::#{superclass}"
        else
          superclass = ''
        end
        
        mod = parent.class_eval <<-end_eval
          #{self.to_s.downcase} #{name}#{superclass}
            self
          end
        end_eval
        
        mod.class_eval(&block) if block_given?
        mod
      end
    end
  end
end

Module.class_eval do
  extend ModuleCreationHelper::Extensions::Module
end
